﻿using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace H.Y.Clipboard
{
	/// <summary>
	/// MainWindow.xaml 的交互逻辑
	/// </summary>
	public partial class MainWindow : Window, HttpClient.IHttpResponseCallback
	{
		private static String SERVER_HOST = "localhost";
		private static int SERVER_PORT = 8000;
		private static String TAG = "HOYIN_MainActivity";
		private static String DATASTORE_TAG_UID = "uid";
		private static String DATASTORE_TAG_NICKNAME = "nickname";
		private static String DATASTORE_TAG_ACCOUNT = "account";
		private HttpClient client;
		private DatabaseOperator.User currentUser;
		private bool isLoginProfileChanged = false;
		private int queryStartAt = 0;
		private bool allQueried = false;

		//List<String> cidList = new List<String>();
		//List<DatabaseOperator.ClipboardItem> items = new List<DatabaseOperator.ClipboardItem>();
		ObservableCollection<DatabaseOperator.ClipboardItem> items = new ObservableCollection<DatabaseOperator.ClipboardItem>();
		ConnectStatus connectStatus = new ConnectStatus();

		public MainWindow()
		{
			InitializeComponent();
			client = new HttpClient(SERVER_HOST, SERVER_PORT, this);

			//测试服务器连接状态
			touchServer();

			//设置无记录的展示列表
			DatabaseOperator.ClipboardItem item = new DatabaseOperator.ClipboardItem();
			String content = "还没有剪贴板记录~";
			item.content = content;
			items.Add(item);
			this.lv_main_clipboard_contents.ItemsSource = items;

			//创建本地数据库
			DatabaseOperator.createUserTable();

			//判断本地数据库有无登录记录，若无则跳转到登录界面
			if (DatabaseOperator.querySignedUser().uid == null)
			{
				main.Visibility = Visibility.Collapsed;
				login.Visibility = Visibility.Visible;
			} else
			{
				main.Visibility = Visibility.Visible;
				login.Visibility = Visibility.Collapsed;
			}

			//获取当前用户
			currentUser = DatabaseOperator.querySignedUser();

			//设置推送输入框的点击事件，主要是点击自动粘贴剪贴板内容
			tbPushBox.AddHandler(Button.MouseUpEvent, new RoutedEventHandler(tbPushBox_MouseButtonUp), true);

			//设置登录按钮的用户名展示
			if (currentUser.nickname != null && currentUser.nickname != "")
			{
				tbNickname.Text = currentUser.nickname;
			}
		}

		private void touchServer()
		{
			string req = Message.generateAliveRequest();
			client.send(req);
		}

		public void onResponse(string response)
		{
			Hashtable hashtable = JsonConvert.DeserializeObject<Hashtable>(response);
			switch (hashtable[Macros.DBTags.ACTION])
			{
                case Macros.Actions.SIGNUP:
                    signUpCallback(response);
                    break;
				case Macros.Actions.ALIVE:
					touchServerCallback(response);
					break;
				case Macros.Actions.LOGIN:
					loginCallback(response);
					break;
				case Macros.Actions.FETCH:
					fetchCallback(response);
                    break;
				case Macros.Actions.QUERY: queryCallback(response); break;
				case Macros.Actions.PUSH: pushCallback(response); break;
            }
				
		}


		private void touchServerCallback(string response)
		{
			Message.AliveResponse resp = JsonConvert.DeserializeObject<Message.AliveResponse>(response);
			if (resp.action != Macros.Actions.ALIVE) return;
			if (resp.status == Macros.Status.SUCCESSFUL) connectStatus.text = "[已连接]";
			else connectStatus.text = "[未连接]";
		}

		private void query(int start=0, int count=10)
		{
			string req = Message.generateQueryRequest(currentUser.uid, start);
			client.send(req);
		}

		private void queryCallback(string response)
		{
			Message.QueryResponse resp = JsonConvert.DeserializeObject<Message.QueryResponse>(response);
			if (resp.action != Macros.Actions.QUERY) return;

			if (resp.status != Macros.Status.SUCCESSFUL)
			{
				if(!resp.reason.Equals(""))
				{
					MessageBox.Show("更新失败，原因是：" + resp.reason, "提示");
				} else
				{
					MessageBox.Show("更新失败，唔知点解");
				}
			}
			else
			{
				Console.WriteLine(resp.start);
				if (resp.start == 0)
                {
                    Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action<List<Message.QueryResponseItem>>(addItem), resp.items);
                } else
				{
                    Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action<List<Message.QueryResponseItem>>(appendItem), resp.items);
                }
			}
		}

		private void addItem(List<Message.QueryResponseItem> respItems)
		{
			items.Clear();
			if (respItems.Count == 0)
			{
				String content = "还没有剪贴板记录~";
				DatabaseOperator.ClipboardItem item = new DatabaseOperator.ClipboardItem();
				item.content = content;
				items.Add(item);
			}
			else
			{
				for (int i = 0; i < respItems.Count; i++)
				{
					DatabaseOperator.ClipboardItem it = new DatabaseOperator.ClipboardItem();
					it.cid = respItems[i].cid;
					it.content = respItems[i].content;
					items.Add(it);
				}
			}
            scrvList.ScrollToVerticalOffset(0);
            this.lv_main_clipboard_contents.ItemsSource = items;
		}

        private void appendItem(List<Message.QueryResponseItem> respItems)
        {
            if (respItems.Count == 0 && !allQueried)
            {
				allQueried = true;
                String content = "已经是最后一条记录了~";
                DatabaseOperator.ClipboardItem item = new DatabaseOperator.ClipboardItem();
                item.content = content;
                items.Add(item);
            }
            else
            {
                for (int i = 0; i < respItems.Count; i++)
                {
                    DatabaseOperator.ClipboardItem it = new DatabaseOperator.ClipboardItem();
                    it.cid = respItems[i].cid;
                    it.content = respItems[i].content;
                    items.Add(it);
                }
            }
            this.lv_main_clipboard_contents.ItemsSource = items;
        }

        private void fetch(string cid)
		{
			string req = Message.generateFetchRequest(cid);
			client.send(req);
		}

		private void fetchCallback(string response)
		{
			Message.FetchResponse resp = JsonConvert.DeserializeObject<Message.FetchResponse>(response);
			if (resp.action != Macros.Actions.FETCH) return;

			if (resp.status != Macros.Status.SUCCESSFUL)
			{
				if (!resp.reason.Equals(""))
				{
					MessageBox.Show("获取失败，原因是：" + resp.reason, "提示");
				}
				else
				{
					MessageBox.Show("获取失败，唔知点解", "提示");
				}
			}
			else
			{
				Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action<string>(displayItem), resp.content);
			}
		}

		private void displayItem(string content)
		{
			tbShowBox.Text = content;
		}

		private void push()
		{
			string req = Message.generatePushRequest(currentUser.uid, String.Format("{0} +08:00", DateTime.Now.ToString()), tbPushBox.Text, Dns.GetHostName());
			client.send(req);
		}
		
		private void pushCallback(string response)
		{
			Message.PushResponse resp = JsonConvert.DeserializeObject<Message.PushResponse>(response);
			if (resp.action != Macros.Actions.PUSH) return;

			if (resp.status != Macros.Status.SUCCESSFUL)
			{
				if (!resp.reason.Equals(""))
				{
					MessageBox.Show("上传失败，原因是：" + resp.reason, "提示");
				}
				else
				{
					MessageBox.Show("上传失败，唔知点解", "提示");
				}
			}
			else
			{
				Thread.Sleep(500);
				Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => {
					query();
					tbPushBox.Text = "";
				}));
			}
		}

		private void signUpCallback(string response)
		{
			Message.SignUpResponse resp = JsonConvert.DeserializeObject<Message.SignUpResponse>(response);
			if (resp.action != Macros.Actions.SIGNUP) return;

			if (resp.status != Macros.Status.SUCCESSFUL)
			{
				if (!resp.reason.Equals(""))
				{
					MessageBox.Show("注册失败，原因是：" + resp.reason, "提示");
				}
				else
				{
					MessageBox.Show("注册失败，唔知点解", "提示");
				}
			}
			else
			{
				MessageBox.Show("注册成功", "提示");
				Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(()=>{
					signup.Visibility = Visibility.Collapsed;
					login.Visibility = Visibility.Visible;
				}));

				}
		}

		private void read(string cid)
        {
			string req = Message.generateReadRequest(cid);
			client.send(req);
        }

        private void readCallback(string response)
        {

        }

        private void btnQuery_Click(object sender, RoutedEventArgs e)
		{
			query();
			allQueried = false;
			queryStartAt = 0;
		}

		private void btnPush_Click(object sender, RoutedEventArgs e)
		{
			if (tbPushBox.Text != "")
			{
				push();
			}
		}

		private void lv_main_clipboard_contents_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			if (lv_main_clipboard_contents.SelectedIndex != -1)
			{
				fetch(items[lv_main_clipboard_contents.SelectedIndex].cid);
				Thread readThread = new Thread((cid) =>
				{
					Thread.Sleep(1000);
					read((string)cid);
				});
				readThread.Start(items[lv_main_clipboard_contents.SelectedIndex].cid);
			}
		}


		private void tbLoginBoxAcc_GotFocus(object sender, RoutedEventArgs e)
		{
			changeImg(accBg, "pack://application:,,,/acc2.png");
		}

		private void tbLoginBoxAcc_LostFocus(object sender, RoutedEventArgs e)
		{
			changeImg(accBg, "pack://application:,,,/acc1.png");
		}

		private void tbLoginBoxPwd_GotFocus(object sender, RoutedEventArgs e)
		{
			changeImg(pwdBg, "pack://application:,,,/pwd2.png");
		}

		private void tbLoginBoxPwd_LostFocus(object sender, RoutedEventArgs e)
		{
			changeImg(pwdBg, "pack://application:,,,/pwd1.png");
		}

		private void btnSignupReturn_Click(object sender, RoutedEventArgs e)
		{
			signup.Visibility = Visibility.Collapsed;
			login.Visibility = Visibility.Visible;
		}

		private void btnSignUp_Click(object sender, RoutedEventArgs e)
		{
			string account = "";
			string password = "";
			string nickname = "";
			if(!(tbSignUpBoxAcc.Text.Count() >= 10 && tbSignUpBoxAcc.Text.Count() <= 18) || !(tbSignUpBoxPwd.Password.Count() >= 10 && tbSignUpBoxPwd.Password.Count() <= 18))
			{
				MessageBox.Show("账号密码长度要求在 10 ~ 18 位之间", "提示");
			}
			else if (tbNkname.Text == "")
			{
				MessageBox.Show("请输入你的名字", "提示");
			}
			else
			{
				if(tbSignUpBoxPwd.Password != tbSignUpBoxRepeatPwd.Password)
				{
					MessageBox.Show("两次输入密码不一致", "提示");
				}
				else if (!FormChecker.isOnlyLetterAndNumber(tbSignUpBoxAcc.Text))
				{
					MessageBox.Show("账号只能包含数字和字母", "提示");
				}
				else
				{
					account = tbSignUpBoxAcc.Text;
					password = tbSignUpBoxPwd.Password;
					nickname = tbNkname.Text;
					string req = Message.generateSignUpRequest(nickname, account, password);
					client.send(req);
				}
			}
		}

		private void tbNkname_GotFocus(object sender, RoutedEventArgs e)
		{
			changeImg(nknameBg, "pack://application:,,,/nickname.png");
		}

		private void tbNkname_LostFocus(object sender, RoutedEventArgs e)
		{
			changeImg(nknameBg, "pack://application:,,,/nickname_1.png");
		}

		private void changeImg(Image image, string path)
		{
			try
			{
				Uri uri = new Uri(path, UriKind.Absolute);
				image.Source = new BitmapImage(uri);
			}
			catch (Exception ex)
			{
				System.Diagnostics.Debug.WriteLine(ex.Message);
			}
		}

		private void tbSignUpBoxAcc_GotFocus(object sender, RoutedEventArgs e)
		{
			changeImg(accSignUpBg, "pack://application:,,,/acc2.png");
		}

		private void tbSignUpBoxAcc_LostFocus(object sender, RoutedEventArgs e)
		{
			changeImg(accSignUpBg, "pack://application:,,,/acc1.png");

		}

		private void tbSignUpRepeatPwd_GotFocus(object sender, RoutedEventArgs e)
		{
			changeImg(pwdSignUpRepeatBg, "pack://application:,,,/pwd_repeat2.png");

		}

		private void tbSignUpBoxRepeatPwd_LostFocus(object sender, RoutedEventArgs e)
		{
			changeImg(pwdSignUpRepeatBg, "pack://application:,,,/pwd_repeat1.png");

		}

		private void tbSignUpBoxPwd_GotFocus(object sender, RoutedEventArgs e)
		{
			changeImg(pwdSignUpBg, "pack://application:,,,/pwd2.png");

		}

		private void tbSignUpBoxPwd_LostFocus(object sender, RoutedEventArgs e)
		{
			changeImg(pwdSignUpBg, "pack://application:,,,/pwd1.png");

		}

		private void btnGoToSignUp_Click(object sender, RoutedEventArgs e)
		{
			login.Visibility = Visibility.Collapsed;
			signup.Visibility = Visibility.Visible;

			tbSignUpBoxAcc.Text = "";
			tbSignUpBoxPwd.Password = "";
			tbSignUpBoxRepeatPwd.Password = "";
			tbNkname.Text = "";
		}

		private void btnLogin_Click(object sender, RoutedEventArgs e)
		{
			
			if(!FormChecker.isOnlyLetterAndNumber(tbLoginBoxAcc.Text))
            {
				MessageBox.Show("账号不存在", "提示");
				return;
            }
			
			if (tbLoginBoxAcc.Text == "" && tbLoginBoxPwd.Password == "")
			{
				MessageBox.Show("请输入账号和密码", "提示");
				return;
			}
			else if (!isLoginProfileChanged)
			{
				main.Visibility = Visibility.Visible;
				login.Visibility = Visibility.Collapsed;
				return;
			}
			else
            {
				string req = Message.generateLoginRequest(tbLoginBoxAcc.Text, tbLoginBoxPwd.Password);
				client.send(req);
				
            }
		}

		private void loginCallback(string response)
		{
			Message.LoginResponse resp = JsonConvert.DeserializeObject<Message.LoginResponse>(response);
			if (resp.action != Macros.Actions.LOGIN) return;
			if (resp.status != Macros.Status.SUCCESSFUL)
			{
				if (!resp.reason.Equals(""))
				{
					MessageBox.Show("登录失败，原因是：" + resp.reason, "提示");
				}
				else
				{
					MessageBox.Show("登录失败，唔知点解", "提示");
				}
			}
			else
			{
				Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => {
					DatabaseOperator.User user = new DatabaseOperator.User();
					user.nickname = resp.nickname;
					user.account = resp.account;
					user.uid = resp.uid;
					user.signed = 1;
					DatabaseOperator.setAllUserUnsigned();
					if (DatabaseOperator.queryUser(resp.uid).uid == null) {
						DatabaseOperator.insertUser(user);
					} else
					{
						DatabaseOperator.setUserSigned(user.uid);
					}
					currentUser = DatabaseOperator.querySignedUser();
					if (currentUser.nickname != null && currentUser.nickname != "")
					{
						tbNickname.Text = currentUser.nickname;
					}
					login.Visibility = Visibility.Collapsed;
					main.Visibility = Visibility.Visible;
					allQueried = false;
					queryStartAt = 0;
				}));
			}
		}

		private void btnGotoLoginClick(object sender, RoutedEventArgs e)
		{
			main.Visibility = Visibility.Collapsed;
			login.Visibility = Visibility.Visible;
			tbLoginBoxAcc.Text = currentUser.account;
			tbLoginBoxPwd.Password = "**********";
			isLoginProfileChanged = false;
		}

		private void main_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
		{
			if(main.Visibility == Visibility.Visible)
			{
				query();
			}
		}

        private void tbLoginBoxAcc_TextChanged(object sender, TextChangedEventArgs e)
        {
			isLoginProfileChanged = true;
			DatabaseOperator.setAllUserUnsigned();
			tbLoginBoxPwd.Password = "";
        }

        private void tbLoginBoxPwd_PasswordChanged(object sender, RoutedEventArgs e)
        {
			isLoginProfileChanged = true;
			DatabaseOperator.setAllUserUnsigned();
		}

        private void btnCopy_Click(object sender, RoutedEventArgs e)
        {
			System.Windows.Clipboard.SetData(DataFormats.UnicodeText, (Object)tbShowBox.Text);
        }

        private void tbPushBox_GotFocus(object sender, RoutedEventArgs e)
        {
			if (tbPushBox.Text == "")
			{
				tbPushBox.Text = System.Windows.Clipboard.GetText();
				tbPushBox.SelectAll();
				tbPushBox.Tag = "new";
			}
		}

        private void tbPushBox_MouseButtonUp(object sender, RoutedEventArgs e)
        {
			if (tbPushBox.Tag == null) return;
			if((string)tbPushBox.Tag == "new")
            {
				tbPushBox.SelectAll();
            }
			tbPushBox.Tag = null;
		}

        private void tb_main_header_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
			MessageBox.Show(@"H.Y.Clipboard
作者: Hoyin
Email: work_hoyin@163.com", "关于");
        }

        private void scrvList_scrollChanged(object sender, ScrollChangedEventArgs e)
        {
			//Console.WriteLine(scrvList.VerticalOffset + scrvList.ViewportHeight + "   |   " + scrvList.ExtentHeight + "  |  " + (scrvList.VerticalOffset + scrvList.ViewportHeight == scrvList.ExtentHeight) as string);
            if ((int)(scrvList.VerticalOffset + scrvList.ViewportHeight) == (int)scrvList.ExtentHeight && !allQueried)
            {
                queryStartAt += 10;
                query(queryStartAt);
				Console.Out.WriteLine("End");
            }
        }

        private void scrvList_mouseWheel(object sender, MouseWheelEventArgs e)
        {
			
			scrvList.ScrollToVerticalOffset(scrvList.VerticalOffset - 0.3*e.Delta);
        }
    }
}
